//
// Created by tang on 23-3-4.
//
#include "app/application_base.hpp"
#include <core/assert.hpp>
#include <core/timespan.hpp>
#include "argparse.hpp"
#include "job/js.hpp"
#include "system/system_private.hpp"
#include "utils/crash_handler.hpp"

using namespace argparse;

static struct {
    bool            run_flag;
    ArgumentParser *args = nullptr;
} app_data;

static IApplication *application_inst = nullptr;

IApplication::IApplication (int argc, const char **argv)
{
    PI_ASSERT (application_inst == nullptr);
    application_inst = this;

    app_data.args = new ArgumentParser ("PiInfoApp");
    app_data.args->add_argument ("-w", "--width");
    app_data.args->add_argument ("-h", "--height");
    app_data.args->add_argument ("-f", "--font_scale");
    try
    {
        app_data.args->parse_args (argc, argv);
    }
    catch (...)
    {
        PI_ASSERT_MSG (0, "Failed to parse arguments");
    }

    install_crash_handlers();
}

IApplication::~IApplication ()
{
    application_inst = nullptr;
    delete app_data.args;
    app_data.args = nullptr;
}

void IApplication::run ()
{
    js_init(0);
    if (initialize ())
    {
        app_data.run_flag = true;

        // time calc
        const pi_time_t begin_run   = platform_get_time ();
        pi_time_t       last_update = begin_run;

        while (app_data.run_flag)
        {
            pi_time_t const current_time = platform_get_time ();
            pi_time_t const total = current_time - begin_run;
            pi_time_t const delta = current_time - last_update;

            // pre tick
            pre_tick_systems();

            // tick
            tick_systems(delta, total);
            update (delta, total);

            // after tick
            after_tick_systems();

            last_update = current_time;
        }

        cleanup();
    }
    else
    {
        L_FATAL ("Application(@%p) initialize failed!", this);
    }
    js_terminate();
}

void IApplication::quit ()
{
    app_data.run_flag = false;
}

IApplication *IApplication::instance ()
{
    return application_inst;
}

rttr::variant IApplication::get_option (std::string_view key, rttr::variant def)
{
    if (app_data.args->is_used (key)) {
        return app_data.args->get (key);
    } else
        return def;
}

void IApplication::install_crash_handlers()
{
    system_install_handlers();
}
